package com.imooc.aop.aspectj;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

//使用注解方式定义切面
@Component
@Aspect
public class MoocAspect {
	//定义了一个切入点 pointcut()
	@Pointcut("execution(* com.imooc.aop.aspectj.biz.*Biz.*(..))")
	public void pointcut() {}
	//限定范围的切入点
	@Pointcut("within(com.imooc.aop.aspectj.biz.*)")
	public void bizPointcut() {}
	//before advice 切入点为上面定义的pointcut()方法，也可直接写excution(...)
	@Before("pointcut()")
	public void before() {
		System.out.println("Before.");
	}
	
	//给advice传递参数  固定写法：args(具体参数名字)
	@Before("pointcut() && args(arg)")
	public void beforeWithParam(String arg) {
		System.out.println("BeforeWithParam." + arg);
	}
	//@annotation 限定匹配特定连接点的主体具有给定的注解， 下面MoocMethod为自定义的注解
	@Before("pointcut() && @annotation(moocMethod)")
	public void beforeWithAnnotaion(MoocMethod moocMethod) {
		//打印自定义注解里面的value()值
		System.out.println("BeforeWithAnnotation." + moocMethod.value());
	}
	
	//returning为绑定返回值，指的是获取目标方法返回后的值
	@AfterReturning(pointcut="bizPointcut()", returning="returnValue")
	public void afterReturning(Object returnValue) {
		System.out.println("AfterReturning : " + returnValue);
	}
	
	//throwing为绑定返回的异常值，指的是获取目标方法抛出的异常
	@AfterThrowing(pointcut="pointcut()", throwing="e")
	public void afterThrowing(RuntimeException e) {
		System.out.println("AfterThrowing : " + e.getMessage());
	}
	
	@After("pointcut()")
	public void after() {
		System.out.println("After.");
	}

	//环绕通知，第一个参数必须为ProceedingJoinPoint类型
	@Around("pointcut()")
	public Object around(ProceedingJoinPoint pjp) throws Throwable {
		System.out.println("Around 1.");
		Object obj = pjp.proceed();
		System.out.println("Around 2.");
		System.out.println("Around : " + obj);
		//不管目标方法有没有返回值，即使是void，这里必须要返回
		return obj;
	}
	
}
